﻿// Welcome to BM Project
// For help, please contact me at https://fb.com/f.i.n.0ne

namespace BM.GUI
{
    using System;
    using System.Diagnostics;
    using System.Drawing;
    using System.IO;
    using System.Threading.Tasks;
    using System.Windows.Forms;

    using Common;
    using Core;
    using Renci.SshNet;

    public partial class fMain : Form
    {
        private string _backUpPath;             // backup path
        private int _backUpOpenCount;           // backup has openned
        private int _backUpIndex;               // index of backup        
        private int _SSHIndex;                  // index of item in ssh list

        private Agent _bmAgent;                 // Bluestack Employee              
        private SshClient _client;              // SSH client
        private ForwardedPortDynamic _proxy;    // Dynamic Forwarded Port

        public fMain()
        {
            InitializeComponent();

            Log.Create();

            var scr = Screen.GetWorkingArea(this);
            this.Top = 0;
            this.Left = scr.Width - this.Width;
            this.Height = scr.Height;

            try {
                // true is bs super change
                // false is xchanger          
                this._bmAgent = new Agent(false);
                this.LoadDataToGridView();
            }
            catch (Exception ex) {
                MessageBox.Show("Lỗi khởi tạo : " + ex.Message, "Boot", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Process.GetCurrentProcess().Kill();
            }
        }

        private async void _btnCreateBackUp_Click(object sender, EventArgs e)
        {
            this._btnCreateBackUp.Enabled = false;
            this._btnStart.Enabled = false;
            this._btnStop.Enabled = false;
            this._progressBar.Visible = true;
            this._lStatus.Text = "Đang tạo backup...";

            var path = Path.Combine(this._bmAgent._bmConfig.BackUpBase, this._txtBackupName.Text);
            await Task.Run(() => this._bmAgent.CreateBackup(path));

            // Update GUI
            this._lStatus.Text = string.Empty;
            this._btnCreateBackUp.Enabled = true;
            this._btnStart.Enabled = true;
            this._btnStop.Enabled = true;
            this._progressBar.Visible = false;

            // Load Data
            this.LoadDataToGridView();
        }

        private async void _btnDeleteBackUp_Click(object sender, EventArgs e)
        {
            // Update GUI
            if (string.IsNullOrEmpty(this._backUpPath)) return;
            this._btnCreateBackUp.Enabled = false;
            this._btnStart.Enabled = false;
            this._btnStop.Enabled = false;
            this._lStatus.Text = "Đang xóa...";

            var path = Path.Combine(this._bmAgent._bmConfig.BackUpBase, this._backUpPath);
            await Task.Run(() => this._bmAgent.DeleteBackup(path));

            // Update GUI
            this._lStatus.Text = string.Empty;
            this._btnCreateBackUp.Enabled = true;
            this._btnStart.Enabled = true;
            this._btnStop.Enabled = true;

            // Update Data
            this.LoadDataToGridView();
        }

        private async void _btnStart_Click(object sender, EventArgs e)
        {
            try {
                // Prevent start duplicate
                this._btnStart.Enabled = false;
                this._btnStop.Enabled = true;

                // Kiểm tra số lượng SSH
                var totalSSH = _lbSSH.Items.Count;
                if (totalSSH == 0) throw new Exception("No SSH");

                Log.Write("Sự kiện Start Backup");

                // Kiểm tra nếu backup đã chạy hết thì chạy lại từ đầu
                if (this._backUpIndex == this._dgv.Rows.Count)
                    this._backUpIndex = 0;

                // Phần : Kết nối SSH
                await Task.Run(() => {
                    // Chú ý: Có thể bị lặp vô hạn nếu toàn bộ SSH không sử dụng được
                    do {
                        // Nếu chạy hết SSH, lặp lại từ đầu
                        if (_SSHIndex == totalSSH) this._SSHIndex = 0;
                        // Lấy SSH hiện tại, tăng chỉ số SSH sang SSH tiếp theo
                        var SSH = this._lbSSH.Items[this._SSHIndex++].ToString().Split('|');

                        Log.Write("Kết nối đến " + SSH[0]);

                        // Cập nhật giao diện
                        this.Invoke(new Action(() => _lStatus.Text = "Kết nối đến " + SSH[0]));
                        // Kết nối SSH
                        this._client = new SshClient(SSH[0], 22, SSH[1], SSH[2]);
                        try {
                            _client.Connect();
                        }
                        catch (Exception ex) {
                            // Không throw, thử kết nối đến SSH tiếp theo
                            Log.Write("Kết nối gặp sự cố " + ex.Message);
                        }
                    }
                    while (!_client.IsConnected);

                    Log.Write("Kết nối thành công, bắt đầu mở cổng.");

                    // Tạo tunnel để truyền dữ liệu
                    _proxy = new ForwardedPortDynamic("127.0.0.1", (uint) _nUDProxyPort.Value);
                    _client.AddForwardedPort(_proxy);
                    try {
                        // Bắt đầu tunnel
                        _proxy.Start();
                    }
                    catch (Exception ex) {
                        // Lỗi mở tunnel do proxy port đã được sử dụng, throw
                        Log.Write("Mở cổng thất bại do " + ex.Message);
                        throw;
                    }
                });

                // Phần : Mở Bluestack                
                await Task.Run(() => {
                    try {
                        Log.Write("Khởi động backup");
                        // Lấy thư mục chứa backup
                        this._backUpPath = this._dgv.Rows[this._backUpIndex].Cells[1].Value.ToString();
                        // Mở backup
                        this._bmAgent.StartBackup(this._backUpPath, "");
                        Log.Write("Khởi động backup thành công");
                        // Tăng số lượng backup đã mở
                        this._backUpOpenCount++;
                        // Cập nhật giaodienej
                        this._lBackUpCount.Text = "Backup đã mở : " + this._backUpOpenCount;
                        this._lStatus.Text = "Đang chạy backup " + this._backUpIndex;
                        this._dgv.Rows[this._backUpIndex].DefaultCellStyle.BackColor = Color.Green;
                    }
                    catch (Exception ex) {
                        Log.Write("Backup không thể mở vì " + ex.Message);
                        throw;
                    }
                });

            }
            catch (Exception ex) {
                // TODO: Exception handler
                Log.Write("Lỗi khi chạy sự kiện Start : " + ex.Message);
                MessageBox.Show("Thông tin lỗi : " + ex.Message, "Start error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                // Khôi phục GUI               
                _lStatus.Text = string.Empty;
                _btnStart.Enabled = true;
                _btnStop.Enabled = false;
            }
        }

        private async void _btnStop_Click(object sender, EventArgs e)
        {
            try {
                // Prevent stop multiple time
                this._btnStop.Enabled = false;

                // Log this action
                Log.Write("Sự kiện dừng backup");

                // Stop backup
                var closeSuccess = false;
                do {
                    try {
                        Log.Write("Dừng backup!");

                        await Task.Run(() => {
                            try {
                                // TOOD: Check
                                this._bmAgent.StopBackup(this._backUpPath);
                                Log.Write("Dừng backup thành công!");
                                return;
                            }
                            catch (Exception ex) {
                                Log.Write("Dừng backup gặp sự cố : " + ex.Message);
                                throw;
                            }
                        });

                        closeSuccess = true;
                    }
                    catch { }
                }
                while (!closeSuccess);

                // reset SSH
                var resetSSHSuccess = false;
                do {
                    try {
                        Log.Write("Ngừng proxy");
                        await Task.Factory.StartNew(() => {
                            try {
                                if (null != _proxy)
                                    _client.RemoveForwardedPort(_proxy);
                                if (this._client.IsConnected)
                                    _client.Disconnect();
                                if (_client != null)
                                    this._client.Dispose();
                                Log.Write("Ngừng proxy thành công!");
                            }
                            catch (Exception ex) {
                                Log.Write("Ngừng proxy gặp sự cố : " + ex.Message);
                                throw;
                            }
                        });
                        resetSSHSuccess = true;
                    }
                    catch {
                        // ???
                    }
                }
                while (!resetSSHSuccess);

                // Cập nhật
                _lStatus.Text = string.Empty;
                _btnStart.Enabled = true;
            }
            catch (Exception ex) {
                Log.Write("Sự kiện lỗi ngừng backup " + ex.Message);
                MessageBox.Show("Thông tin lỗi : " + ex.Message, "Stop error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void _btnImportSSH_Click(object sender, EventArgs e)
        {
            using (var open = new OpenFileDialog()) {
                if (open.ShowDialog() == DialogResult.OK) {
                    var SSHs = File.ReadAllLines(open.FileName);
                    this._lbSSH.Items.Clear();
                    this._lbSSH.Items.AddRange(SSHs);
                    this._sshLabel.Text = "Tổng cộng " + SSHs.Length;
                }
            }
        }

        private void _btnClearSSH_Click(object sender, EventArgs e)
        {
            _lbSSH.Items.Clear();
        }

        private void _btnOpenConfig_Click(object sender, EventArgs e)
        {
            using (var config = new fConfig()) {
                config.ShowDialog();
                this._bmAgent._bmConfig = BMConfig.LoadSetting();
                this.LoadDataToGridView();
            }

        }

        private void _dgv_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex < 0) return;
            this._backUpIndex = e.RowIndex;
            this._backUpPath = this._dgv.Rows[e.RowIndex].Cells[1].Value.ToString();
            this._lStatus.Text = "Backup " + e.RowIndex + " has been selected.";
        }

        private void _main_FormClosing(object sender, FormClosingEventArgs e)
        {
            var closeResult = MessageBox.Show("Bạn muốn thoát không?", "Close", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk);

            if (closeResult == DialogResult.No) {
                e.Cancel = true;
                return;
            }

            if (this._btnStop.Enabled) {
                this._lStatus.Text = "Đang thoát BlueStack";
                this._btnStop.PerformClick();
                this._lStatus.Text = "Đang thoát...";
                Log.Close();
            }
        }

        private void LoadDataToGridView()
        {
            this._dgv.Rows.Clear();

            var backUpPaths = this._bmAgent._bmConfig.BackUps;
            if (backUpPaths.Count != 0) {
                foreach (var backUpPath in backUpPaths) {
                    var row = this._dgv.Rows.Add();
                    this._dgv.Rows[row].Cells[0].Value = row;
                    this._dgv.Rows[row].Cells[1].Value = backUpPath;
                }
            }
            else {
                this._lStatus.Text = "Không có backup!";
            }
        }
    }
}